package com.example.demo003argsresolver.config;

import com.example.demo003argsresolver.domain.TranUserVo;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Map;

/**
 * 在微服务场景中有个特别常见的现象：跟第三方服务做对接时（如 python 老系统），你不乏会遇到如下两个痛点：
 *  1. 对方系统是以下划线形式命名的（和Java命名规范相悖）
 *  2. 对方系统的参数json串层次较深，而对你有用的仅仅是深处的一小部分
 * {
 *     "data": {
 *         "transport_data": {
 *             "demo_name": "fsx",
 *             "demo_age": 18
 *         },
 *         "secret_info": {
 *             "code": "fkldshjfkldshj"
 *         }
 *     },
 *     "code": "200",
 *     "msg": "this is a message"
 * }
 * 对你真正有用的只有demo_name和demo_age两个值，怎么破？？？
 *
 * 自定义一个参数解析器并且注册
 */
public class TranUserArgumentResolver implements HandlerMethodArgumentResolver {
    // 只处理 TranUserVo 这个类型，不需要注解
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class<?> parameterType = parameter.getParameterType();
        return TranUserVo.class.isAssignableFrom(parameterType);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod());
        String value ;
        // 本例为了简单，演示get的情况（这里使用key为：demoKey）
        if (httpMethod == HttpMethod.GET){
            value = request.getParameter("demoKey");
        }else {
            ServletInputStream is = request.getInputStream();
            byte[] buf = new byte[1024];
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            int len = 0;
            while ((len = is.read(buf)) != -1){
                os.write(buf,0,len);
            }
            value = os.toString();
        }

        Map<String,Object> map = new ObjectMapper().readValue(value, new TypeReference<Map<String, Object>>() {});
        Map<String, Object> data = (Map<String, Object>) map.get("data");
        Map<String, Object> transportData = (Map<String, Object>) data.get("transport_data");

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);//下划线转驼峰
        TranUserVo tranUserVo = objectMapper.readValue(new ObjectMapper().writeValueAsString(transportData), TranUserVo.class);
        return tranUserVo;
    }

}
